package api

import (
	"context"
	"errors"
	"gitee.com/go-caipu-team/go-caipu-plugin-sdk/pkg/utils"
	"github.com/gin-gonic/gin"
	"go-caipu/pkg/api/helper"
	"go-caipu/pkg/constant"
	"go-caipu/pkg/services/admin/config"
	"go-caipu/pkg/util"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"go-caipu/pkg/services/storage/models"
)

// DownLocalFileHandler 下载本地文件（仅限于单机部署的情况，如果多机部署需要挂载相同访问目录）
func (hs *HTTPServer) DownLocalFileHandler(c *gin.Context) {
	url := c.Param("url")
	store, err := hs.storageService.GetFileInfo(url)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	if store.StorageType != models.StorageLocal {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, errors.New("file not found"))
		return
	}
	config, err := hs.storageService.GetStorageConfigByType(store.StorageType)
	if err != nil {
		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, errors.New("file storage config not found"))
		return
	}
	pluginPath := filepath.Join(config.BucketName, url)
	// 处理文件不存在的情况 或者 扩展名
	if _, err := os.Stat(pluginPath); err != nil {
		c.JSON(404, "文件不存在")
		return
	}
	c.File(pluginPath)
}

// 文件/路径名保留字符
var reservedCharacter = []string{"\\", "?", "*", "<", "\"", ":", ">", "/", "|"}

// ValidateUploadMiddleware 文件上传中间件（检查文件是否满足上传条件）
func (hs *HTTPServer) ValidateUploadMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		file, err := c.FormFile("file")
		//获取上传配置
		items, err := hs.configService.GetConfigsByKey(c.Request.Context(), config.GetConfigsByKeyCommand{Category: "upload_"})
		if err != nil {
			helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
			c.Abort()
			return
		}
		//判断文件名
		if !validateFileName(file.Filename) {
			helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, errors.New("文件名不合法"))
			c.Abort()
			return
		}
		//判断文件大小和文件类型
		for _, item := range items {
			value := item.ConfigValue.(string)
			//判断文件大小
			if item.ConfigKey == "UPLOAD_MAXSIZE" {
				maxSize := util.StringToInt64(value)
				if maxSize != 0 && file.Size > maxSize {
					helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, errors.New("文件大小超过限制"))
					c.Abort()
					return
				}
			}
			//判断文件类型
			if item.ConfigKey == "UPLOAD_FILETYPE" {
				//
				if value == "*" {
					continue
				}
				fileType := util.StringToArr(value)
				ext := file.Filename[strings.LastIndex(file.Filename, ".")+1:]
				if !util.Contains(fileType, ext) {
					helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, errors.New("文件类型不支持"))
					c.Abort()
					return
				}
			}
		}
		c.Next()
	}
}
func validateFileName(name string) bool {
	// 是否包含保留字符
	for _, value := range reservedCharacter {
		if strings.Contains(name, value) {
			return false
		}
	}

	// 是否超出长度限制
	if len(name) >= 256 {
		return false
	}

	// 是否为空限制
	if len(name) == 0 {
		return false
	}

	// 结尾不能是空格
	if strings.HasSuffix(name, " ") {
		return false
	}
	return true
}

// Upload 上传文件
func (hs *HTTPServer) Upload(ctx *gin.Context) {
	// 获取上传的文件
	file, err := ctx.FormFile("file")
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	model := models.FileStorage{
		FileName: file.Filename,
		FileSize: file.Size,
	}
	// 获取存储类型
	model.StorageType = models.StorageType(ctx.PostForm("storage_type"))
	model.CreatedBy = hs.getJwtUserID(ctx)
	model.CreatedAt = time.Now()
	model.UpdatedAt = time.Now()

	reader, err := file.Open()
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	defer reader.Close()
	err = hs.storageService.Upload(ctx, &model, reader)
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithData(ctx, model)
}

// DownLoad 获取文件信息
func (hs *HTTPServer) DownLoad(ctx *gin.Context) {
	fileKey := ctx.Param("file_key")

	content, fileStorage, err := hs.storageService.DownLoad(ctx.Request.Context(), fileKey)
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	defer content.Close()
	dat, err := io.ReadAll(content)
	if err != nil {

	}
	ctx.Header("Content-Disposition", "inline; filename="+fileStorage.FileName)
	ctx.Data(200, http.DetectContentType(dat), dat)
}

// GetFileUrlHandler 获取文件下载址(后续会加签名验证)
func (hs *HTTPServer) GetFileUrlHandler(ctx *gin.Context) {
	fileKey := ctx.Param("file_key")
	url, err := hs.storageService.GetFileUrl(context.Background(), fileKey)
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	ctx.Redirect(302, url)
}

// DeleteFile 删除文件
func (hs *HTTPServer) DeleteFile(ctx *gin.Context) {
	fileKey := ctx.Param("file_key")
	//删除文件操作
	err := hs.storageService.DeleteFile(ctx, fileKey)
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithData(ctx, "success")
}

// 存储配置管理

// CreateStorageConfig 创建存储配置
func (hs *HTTPServer) CreateStorageConfig(ctx *gin.Context) {
	var config models.StorageConfig
	if err := ctx.ShouldBindJSON(&config); err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, err)
		return
	}
	//前端解密数据
	accessKey := hs.Cfg.DecryptedData(config.SecretKey)
	encrypt := utils.New(hs.Cfg.Application.EncryptionKey)
	config.SecretKey, _ = encrypt.Encrypt(accessKey) //加密后的数据

	err := hs.storageService.CreateStorageConfig(&config)
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}

	helper.SuccessWithData(ctx, config)
}

// UpdateStorageConfig 更新存储配置
func (hs *HTTPServer) UpdateStorageConfig(ctx *gin.Context) {
	var config models.StorageConfig
	if err := ctx.ShouldBindJSON(&config); err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, err)
		return
	}
	//前端解密数据
	accessKey := hs.Cfg.DecryptedData(config.SecretKey)
	encrypt := utils.New(hs.Cfg.Application.EncryptionKey)
	config.SecretKey, _ = encrypt.Encrypt(accessKey) //加密后的数据

	err := hs.storageService.UpdateStorageConfig(&config)
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}

	helper.SuccessWithData(ctx, config)
}
func (hs *HTTPServer) UpdateStorageStatus(ctx *gin.Context) {
	id, err := strconv.ParseInt(ctx.Param("id"), 10, 64)
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, err)
		return
	}
	type UpdateStorageStatusCommand struct {
		Status int8 `json:"status"`
	}
	cmd := UpdateStorageStatusCommand{}
	if err := helper.BindAndValidate(ctx, &cmd); err != nil {
		return
	}
	err = hs.storageService.UpdateStatus(id, cmd.Status)
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithData(ctx, "success")
}

// SetDefaultStorageConfig 设置默认存储配置
func (hs *HTTPServer) SetDefaultStorageConfig(ctx *gin.Context) {
	id, err := strconv.ParseInt(ctx.Param("id"), 10, 64)
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, err)
		return
	}

	err = hs.storageService.SetDefaultStorageConfig(id)
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithData(ctx, "success")
}

// ListStorageConfigs 获取存储配置列表
func (hs *HTTPServer) ListStorageConfigs(ctx *gin.Context) {
	storageType := models.StorageType(ctx.Query("type"))
	name := ctx.Query("description")
	configs, err := hs.storageService.ListStorageConfigs(storageType, name)
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithData(ctx, configs)
}
func (hs *HTTPServer) GetStorageConfig(ctx *gin.Context) {
	id, err := strconv.ParseInt(ctx.Param("id"), 10, 64)
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrBadRequest, constant.ErrTypeInternalServer, err)
		return
	}
	config, err := hs.storageService.GetStorageConfig(id)
	config.SecretKey = "********" // 前端展示时，隐藏敏感信息
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithData(ctx, config)
}

type DeleteStorageConfigCommand struct {
	Ids []int64 `json:"ids"`
}

// DeleteStorageConfig 删除存储配置
func (hs *HTTPServer) DeleteStorageConfig(ctx *gin.Context) {
	cmd := DeleteStorageConfigCommand{}
	if err := helper.BindAndValidate(ctx, &cmd); err != nil {
		return
	}

	err := hs.storageService.DeleteStorageConfig(cmd.Ids)
	if err != nil {
		helper.ErrorWithDetail(ctx, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
		return
	}
	helper.SuccessWithData(ctx, "存储配置删除成功")
}
